#include "stdafx.h"
#include "ShellLink.h"




//////////////// Macros / Locals /////////////////////////////////////

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif



//////////////// Implementation //////////////////////////////////////

CShellLinkInfo::CShellLinkInfo()
{
	//Set up some reasonable defaults
	m_pidl = NULL;
	m_wHotkey = 0;
	m_nIconIndex = 0;
	m_nShowCmd = SW_SHOW;
}

CShellLinkInfo::CShellLinkInfo(const CShellLinkInfo& sli)
{
	*this = sli;
}

CShellLinkInfo::~CShellLinkInfo()
{
	// Get the shell's allocator. 
	IMalloc* pMalloc;
	HRESULT hRes = SHGetMalloc(&pMalloc);
	if (!SUCCEEDED(hRes)) 
	{
		return;
	}

	//Free the pidl
	if (m_pidl)
	{
		pMalloc->Free(m_pidl);
		m_pidl = NULL;
	}

	// Release the pointer to IMalloc
	pMalloc->Release(); 
}

CShellLinkInfo& CShellLinkInfo::operator=(const CShellLinkInfo& sli)
{
	m_sTarget = sli.m_sTarget;
	m_pidl = sli.m_pidl;
	m_sArguments = sli.m_sArguments;
	m_sDescription = sli.m_sDescription;
	m_wHotkey = sli.m_wHotkey;
	m_sIconLocation = sli.m_sIconLocation;
	m_nIconIndex = sli.m_nIconIndex;
	m_nShowCmd = sli.m_nShowCmd;
	m_sWorkingDirectory = sli.m_sWorkingDirectory;

	return *this;
}

CShellLink::CShellLink()
{
	m_psl = NULL;
	m_ppf = NULL;
	m_bAttemptedInitialise = FALSE;
}

CShellLink::~CShellLink()
{
	if (m_ppf)
	{
		m_ppf->Release();
		m_ppf = NULL;
	}
	if (m_psl)
	{
		m_psl->Release();
		m_psl = NULL;
	}
}

BOOL CShellLink::Initialise()
{
	BOOL bSuccess = FALSE;
	if (m_bAttemptedInitialise)
		bSuccess = (m_psl != NULL);
	else
	{
		//Instantiate the COM class
		HRESULT hRes = ::CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*) &m_psl);
		if (SUCCEEDED(hRes))
		{
			//Also get a pointer to IPersistFile
			hRes = m_psl->QueryInterface(IID_IPersistFile, (LPVOID*) &m_ppf);
			bSuccess = SUCCEEDED(hRes);
		}

		m_bAttemptedInitialise = TRUE;
	}

	return bSuccess;
}

BOOL CShellLink::Create(const CShellLinkInfo& sli)
{
	if (!Initialise())
		return FALSE;

	m_sli = sli;

	return TRUE;
}

BOOL CShellLink::Save(const std::wstring& sFilename)
{
	if (!Initialise())
		return FALSE;

	BOOL bSuccess = FALSE;
	HRESULT hRes;

	//Convert the path to a UNICODE string
	WCHAR wszPath[MAX_PATH];

	_tcscpy_s(wszPath, MAX_PATH, sFilename.c_str());

	//Set the various link values
	if (m_sli.m_pidl)
	{
		hRes = m_psl->SetIDList(m_sli.m_pidl);
	}
	else
	{
		hRes = m_psl->SetPath(m_sli.m_sTarget.c_str());
	}

	hRes = m_psl->SetWorkingDirectory(m_sli.m_sWorkingDirectory.c_str());

	hRes = m_psl->SetIconLocation(m_sli.m_sIconLocation.c_str(), m_sli.m_nIconIndex);

	hRes = m_psl->SetDescription(m_sli.m_sDescription.c_str());

	hRes = m_psl->SetArguments(m_sli.m_sArguments.c_str());

	hRes = m_psl->SetHotkey(m_sli.m_wHotkey);

	hRes = m_psl->SetShowCmd(m_sli.m_nShowCmd);

	//Save the link to file
	hRes = m_ppf->Save(wszPath, TRUE);
	if (SUCCEEDED(hRes))
		bSuccess = TRUE;

	return bSuccess;
}

BOOL CShellLink::Load(const std::wstring& sFilename)
{
	if (!Initialise())
		return FALSE;

	BOOL bSuccess = FALSE;

	//Convert the path to a UNICODE string
	WCHAR wszPath[MAX_PATH];

	_tcscpy_s(wszPath, MAX_PATH, sFilename.c_str());

	//Load the link from file
	HRESULT hRes = m_ppf->Load(wszPath, STGM_READ);
	if (SUCCEEDED(hRes))
	{
		//Get the various link values
		TCHAR szBuf[_MAX_PATH];
		WIN32_FIND_DATA fd;

		hRes = m_psl->GetPath(szBuf, _MAX_PATH, &fd, SLGP_UNCPRIORITY);
		if (SUCCEEDED(hRes))
			m_sli.m_sTarget = szBuf;

		hRes = m_psl->GetIDList(&m_sli.m_pidl);

		hRes = m_psl->GetWorkingDirectory(szBuf, _MAX_PATH);
		if (SUCCEEDED(hRes))
			m_sli.m_sWorkingDirectory = szBuf;

		hRes = m_psl->GetIconLocation(szBuf, _MAX_PATH, &m_sli.m_nIconIndex);
		if (SUCCEEDED(hRes))
			m_sli.m_sIconLocation = szBuf;

		hRes = m_psl->GetDescription(szBuf, _MAX_PATH);
		if (SUCCEEDED(hRes))            
			m_sli.m_sDescription = szBuf;

		hRes = m_psl->GetArguments(szBuf, _MAX_PATH);
		if (SUCCEEDED(hRes))
			m_sli.m_sArguments = szBuf;

		hRes = m_psl->GetHotkey(&m_sli.m_wHotkey);

		hRes = m_psl->GetShowCmd(&m_sli.m_nShowCmd);

		bSuccess = TRUE;
	}

	return bSuccess;
}

BOOL CShellLink::Resolve(HWND hParentWnd, DWORD dwFlags)
{
	if (!Initialise())
		return FALSE;

	BOOL bSuccess = FALSE;

	//Do the actual link resolve
	HRESULT hRes = m_psl->Resolve(hParentWnd, dwFlags);

	if (SUCCEEDED(hRes))
		bSuccess = TRUE;

	return bSuccess;
}

std::wstring CShellLink::GetPath() const
{
	return m_sli.m_sTarget;
}

std::wstring CShellLink::GetArguments() const
{
	return m_sli.m_sArguments;
}

std::wstring CShellLink::GetDescription() const
{
	return m_sli.m_sDescription;
}

WORD CShellLink::GetHotKey() const
{
	return m_sli.m_wHotkey;
}

std::wstring CShellLink::GetIconLocation() const
{
	return m_sli.m_sIconLocation;
}

int CShellLink::GetIconLocationIndex() const
{
	return m_sli.m_nIconIndex;
}

LPITEMIDLIST CShellLink::GetPathIDList() const
{
	return m_sli.m_pidl;
}

int CShellLink::GetShowCommand() const
{
	return m_sli.m_nShowCmd;
}

std::wstring CShellLink::GetWorkingDirectory() const
{
	return m_sli.m_sWorkingDirectory;
}

void CShellLink::SetPath(const std::wstring& sPath)
{
	m_sli.m_sTarget = sPath;
}

void CShellLink::SetArguments(const std::wstring& sArguments)
{
	m_sli.m_sArguments = sArguments;
}

void CShellLink::SetDescription(const std::wstring& sDescription)
{
	m_sli.m_sDescription = sDescription;
}

void CShellLink::SetHotKey(WORD wHotkey)
{
	m_sli.m_wHotkey = wHotkey;
}

void CShellLink::SetIconLocation(const std::wstring& sIconLocation)
{
	m_sli.m_sIconLocation = sIconLocation;
}

void CShellLink::SetIconLocationIndex(int nIconIndex)
{
	m_sli.m_nIconIndex = nIconIndex;
}

void CShellLink::SetPathIDList(LPITEMIDLIST pidl)
{
	m_sli.m_pidl = pidl;
}

void CShellLink::SetShowCommand(int nShowCmd)
{
	m_sli.m_nShowCmd = nShowCmd;
}

void CShellLink::SetWorkingDirectory(const std::wstring& sWorkingDirectory)
{
	m_sli.m_sWorkingDirectory = sWorkingDirectory;
}


CUrlShellLink::CUrlShellLink()
{
	m_pURL = NULL;
}

BOOL CUrlShellLink::Create(const CShellLinkInfo& sli)
{
	if (!Initialise())
		return FALSE;

	m_sli = sli;

	return TRUE;
}

CUrlShellLink::~CUrlShellLink()
{
	if (m_psl)
	{
		m_psl->Release();
		m_psl = NULL;
	}
	if (m_ppf)
	{
		m_ppf->Release();
		m_ppf = NULL;
	}
	if (m_pURL)
	{
		m_pURL->Release();
		m_pURL = NULL;
	}
}

BOOL CUrlShellLink::Initialise()
{
	BOOL bSuccess = FALSE;
	if (m_bAttemptedInitialise)
		bSuccess = (m_pURL != NULL);
	else
	{
		//Instantiate the COM class
		HRESULT hRes = ::CoCreateInstance(CLSID_InternetShortcut, NULL, CLSCTX_INPROC_SERVER, IID_IUniformResourceLocator, (LPVOID*) &m_pURL);
		if (SUCCEEDED(hRes))
		{
			//Also get a pointer to IPersistFile
			hRes = m_pURL->QueryInterface(IID_IPersistFile, (LPVOID*) &m_ppf);
			if (SUCCEEDED(hRes))
			{
				//Also get a pointer to IShellLink
				hRes = m_pURL->QueryInterface(IID_IShellLink, (LPVOID*) &m_psl);
				if (SUCCEEDED(hRes))
					bSuccess = TRUE;
			}
		}

		m_bAttemptedInitialise = TRUE;
	}

	return bSuccess;
}

BOOL CUrlShellLink::Save(const std::wstring& sFilename)
{
	if (!Initialise())
		return FALSE;

	BOOL bSuccess = FALSE;

	//Convert the path to a UNICODE string
	WCHAR wszPath[_MAX_PATH];

	_tcscpy_s(wszPath, MAX_PATH, sFilename.c_str());

	//Set the various arguments
	HRESULT hRes = m_pURL->SetURL(m_sli.m_sTarget.c_str(), 0);

	hRes = m_psl->SetIconLocation(m_sli.m_sIconLocation.c_str(), m_sli.m_nIconIndex);

	hRes = m_psl->SetDescription(m_sli.m_sDescription.c_str());

	hRes = m_psl->SetHotkey(m_sli.m_wHotkey);

	//Save the link to file
	hRes = m_ppf->Save(wszPath, TRUE);
	if (SUCCEEDED(hRes))
		bSuccess = TRUE;

	return bSuccess;
}

BOOL CUrlShellLink::Load(const std::wstring& sFilename)
{
	if (!Initialise())
		return FALSE;

	BOOL bSuccess = FALSE;

	//Convert the path to a UNICODE string
	WCHAR wszPath[MAX_PATH];

	_tcscpy_s(wszPath, MAX_PATH, sFilename.c_str());

	//Load the link from file
	HRESULT hRes = m_ppf->Load(wszPath, STGM_READ);
	if (SUCCEEDED(hRes))
	{
		//Get the various link values
		LPTSTR lpTemp = NULL;
		hRes = m_pURL->GetURL(&lpTemp);
		if (lpTemp == NULL)
			return FALSE;
		if (SUCCEEDED(hRes))
		{
			m_sli.m_sTarget = lpTemp;

			IMalloc* pMalloc;
			hRes = SHGetMalloc(&pMalloc); 
			if (SUCCEEDED(hRes))
			{
				pMalloc->Free(lpTemp);
				pMalloc->Release();
			}
		}

		TCHAR szBuf[_MAX_PATH];
		hRes = m_psl->GetWorkingDirectory(szBuf, _MAX_PATH);
		if (SUCCEEDED(hRes))
			m_sli.m_sWorkingDirectory = szBuf;

		hRes = m_psl->GetIconLocation(szBuf, _MAX_PATH, &m_sli.m_nIconIndex);
		if (SUCCEEDED(hRes))
			m_sli.m_sIconLocation = szBuf;

		//WINBUG: URL shortcuts always seem to return a description the same as the name of
		//file in which the shortcut is stored
		hRes = m_psl->GetDescription(szBuf, _MAX_PATH);
		if (SUCCEEDED(hRes))            
			m_sli.m_sDescription = szBuf;

		hRes = m_psl->GetHotkey(&m_sli.m_wHotkey);

		hRes = m_psl->GetShowCmd(&m_sli.m_nShowCmd);

		bSuccess = TRUE;
	}

	return bSuccess;
}

BOOL CUrlShellLink::Invoke(HWND hParentWnd, DWORD dwFlags, const std::wstring& sVerb)
{
	BOOL bSuccess = FALSE;

	URLINVOKECOMMANDINFO urlicmi;
	urlicmi.dwcbSize = sizeof(URLINVOKECOMMANDINFO);
	urlicmi.dwFlags = dwFlags;  
	urlicmi.hwndParent = NULL;
	if (hParentWnd)
		urlicmi.hwndParent = hParentWnd;          
	urlicmi.pcszVerb = sVerb.c_str();

	//Invoke the verb on the URL
	HRESULT hRes = m_pURL->InvokeCommand(&urlicmi);
	if (SUCCEEDED(hRes))
		bSuccess = TRUE;

	return bSuccess;
}

void CUrlShellLink::SetArguments(const std::wstring& /*sArguments*/)
{
	//Arguments are not supported for Internet shortcuts
}

std::wstring CUrlShellLink::GetArguments() const
{
	//Arguments are not supported for Internet shortcuts
	return std::wstring();
}

LPITEMIDLIST CUrlShellLink::GetPathIDList() const
{
	//pidls are not supported for Internet shortcuts
	return NULL;
}

void CUrlShellLink::SetPathIDList(LPITEMIDLIST /*pidl*/)
{
	//pidls are not supported for Internet shortcuts
}

